#include <windows.h>
#include "lib.h"
#include "time.h"
#include "opts.h"

#include "progserv.h"

#include "casbase.h"

ProgressiveTrackSQL* tracker = (ProgressiveTrackSQL*)0;

ProgressiveServer::ProgressiveServer(int port,const String& sAppName)
	: Server(port, sAppName)
{
    pProgInfoList = (PPROGINFO_T) 0;
	tracker = (ProgressiveTrackSQL*)0;
}

ProgressiveServer::~ProgressiveServer()
{
    delProgInfoList();
}

bool8 ProgressiveServer::isProgressiveOn(int32 jackpotID)
{
    PPROGINFO_T pProgInfo = getProgInfo(jackpotID);
    return pProgInfo->progressiveOn;
}


// luke 7/24/02: Modified to load only one jackpot (see TestDirector bug #194)
bool8 ProgressiveServer::loadJackpot(int32 jackpotID, bool8 forReal, int32 fixedAmountMultiplier)
{
    PPROGINFO_T pProgInfo = getProgInfo(jackpotID);

    // NOTE: We are not going to store the jackpot anymore in a local var, so just
    //  store the fixedAmountMultiplier for later.
    pProgInfo->fixedAmountMultiplier = fixedAmountMultiplier;

    return( true );
}


bool8 ProgressiveServer::gameEnabled(int32 jackpotID)
{
	int32 result = ProgressiveTrackSQL::ExecFailed;

	if (tracker)
	{
		tracker->lock();
		result = (((ProgressiveTrackSQL*)tracker))->gameEnabled(jackpotID, ServerOpts::baseName);
		tracker->unlock();
	}
	return (bool8)(result == ProgressiveTrackSQL::NoError);
}


int32 ProgressiveServer::getProgressiveJackpot(int32 jackpotID, bool8 forReal)
{
    int32 result = 0;
    int32 jackpot = 0;

    PPROGINFO_T pProgInfo = getProgInfo(jackpotID);

    if (tracker)
    {
        tracker->lock();
        result = (((ProgressiveTrackSQL*)tracker))->getJackpot(jackpotID, jackpot, forReal, pProgInfo->fixedAmountMultiplier );
        tracker->unlock();
    }

    return jackpot;
}


bool8 ProgressiveServer::placeProgressiveBet(int32 jackpotID, int32 nContributionAmount, int32 betAmount, int32 betMultiplier, bool8 forReal, int32 progressiveFixedAmountMultiplier, int32& multiBankBet)
{
    int32 putInJackpot = nContributionAmount; 
    int32 realJackpot = 0;
    int32 funJackpot = 0;
    long currentBetTime;
    PPROGINFO_T pProgInfo = getProgInfo(jackpotID);

    if (forReal)
    {
        if ( putInJackpot || multiBankBet )
        {
            if (!jackpotAdjust(jackpotID, putInJackpot, realJackpot, true, progressiveFixedAmountMultiplier, multiBankBet ))
            {
                DEBUGMSG(("ProgressiveServer: Error adjusting jackpot by contribution amount."));
                return false;
            }
        }
        else
        {
            if (!jackpotAdjustByBet(jackpotID, betAmount, betMultiplier, realJackpot, putInJackpot, multiBankBet, true, progressiveFixedAmountMultiplier))
        {
            DEBUGMSG(("ProgressiveServer: Error adjusting jackpot by bet amount."));
			return false;
        }
        }

        if (pProgInfo->lastRealBetTime == 0)
        {
            pProgInfo->lastRealBetTime = clock();
        }
        else
        {
            //keep track of the time between this bet and the last, to track the rate of jackpot increase
            currentBetTime = clock();
            if (currentBetTime >= 0)
                pProgInfo->realBets[pProgInfo->realBetIndex].betTime = currentBetTime - pProgInfo->lastRealBetTime;
            else 
                DEBUGMSG(("ProgressiveServer: Error in getting process time."));

            pProgInfo->lastRealBetTime = currentBetTime;
            pProgInfo->realBets[pProgInfo->realBetIndex].amtPutInJackpot = realJackpot;

            if (pProgInfo->realBetIndex >= 99)
                pProgInfo->realBetIndex = 0;
            else
                pProgInfo->realBetIndex++;
        }
        pProgInfo->numRealBets++;
    }
    else
    {
        if ( putInJackpot || multiBankBet )
        {
            if (!jackpotAdjust(jackpotID, putInJackpot, funJackpot, false, progressiveFixedAmountMultiplier, multiBankBet ))
            {
                DEBUGMSG(("ProgressiveServer: Error adjusting jackpot by contribution amount."));
                return false;
            }
        }
        else
        {
            if (!jackpotAdjustByBet(jackpotID, betAmount, betMultiplier, funJackpot, putInJackpot, multiBankBet, false, progressiveFixedAmountMultiplier))
        {
            DEBUGMSG(("ProgressiveServer: Error adjusting jackpot by bet amount."));
			return false;
        }
        }

        if (pProgInfo->lastFunBetTime == 0)
        {
            pProgInfo->lastFunBetTime = clock();
        }
        else
        {
            //keep track of the time between this bet and the last, to track the rate of jackpot increase
            currentBetTime = clock();
            if (currentBetTime >= 0)
                pProgInfo->funBets[pProgInfo->funBetIndex].betTime = currentBetTime - pProgInfo->lastFunBetTime;
            else DEBUGMSG(("ProgressiveServer: Error in getting process time."));

            pProgInfo->lastFunBetTime = currentBetTime;
            pProgInfo->funBets[pProgInfo->funBetIndex].amtPutInJackpot = funJackpot;

            if (pProgInfo->funBetIndex >= 99)
                pProgInfo->funBetIndex = 0;
            else
                pProgInfo->funBetIndex++;
        }
        pProgInfo->numFunBets++;
    }

	return true;
}

// kharmon.  10-05-05.  #5861.  Added bPercentage parameter so that a payrate of less than 100 can 
// optionally be treated as an absolute amount.
bool8 ProgressiveServer::setProgressiveWinner(int32 jackpotID, int32 payrate, bool8 forReal, int32 progressiveFixedAmountMultiplier, int32* pPayout, int32* multiBankPayout, bool bPercentage)
{
	// [AO 2007-08-16] ProgInfo not used
	// PPROGINFO_T pProgInfo = getProgInfo(jackpotID);
    int32 result = ProgressiveTrackSQL::ExecFailed;

    if (tracker)
    {
        tracker->lock();
        result = ((ProgressiveTrackSQL*)tracker)->setProgressiveWinner( ServerOpts::baseName, jackpotID, payrate, forReal, progressiveFixedAmountMultiplier, pPayout, multiBankPayout, bPercentage );
        tracker->unlock();
    }

    return (bool8)(result == ProgressiveTrackSQL::NoError);	
}

void ProgressiveServer::setProgressiveOn(int32 jackpotID, bool8 progressiveOn)
{
    PPROGINFO_T pProgInfo = getProgInfo(jackpotID);

    pProgInfo->progressiveOn = progressiveOn;
}

void ProgressiveServer::setProgressiveJackpotID(int32 jackpotID)
{
    PPROGINFO_T pProgInfo = getProgInfo(jackpotID);
    pProgInfo->jackpotID = jackpotID;  // Unused but left here for consistency with old code.
}




/**
 *      getProgInfo
 *          Get a pointer to a ProgInfo structure.  First check
 *          for an existing ProgInfo structure using the jackpotID.
 *          If none is found, insert a new one and return that.
 *
 *      Parameters
 *          jackpotID   i
 *              The jackpotID used to identify the ProgInfo structure.
 *
 *      Returns
 *          PROGINFO_T *
 *              A pointer to the ProgInfo structure found or created.
 */

PPROGINFO_T ProgressiveServer::getProgInfo(int32 jackpotID)
{
    PPROGINFO_T pProgInfo;

    pProgInfo = findProgInfo(jackpotID);
    if ( pProgInfo == (PPROGINFO_T) 0 )
    {
        pProgInfo = insertProgInfo(jackpotID);
    }

    return pProgInfo;
}



/**
 *      findProgInfo
 *          Search for an existing ProgInfo structure using the 
 *          jackpotID.  If none is found, return a null.
 *
 *      Parameters
 *          jackpotID   i
 *              The jackpotID used to identify the ProgInfo structure.
 *
 *      Returns
 *          PROGINFO_T *
 *              A pointer to the ProgInfo structure found.
 *          null
 *              No such jackpotID found.
 */

PPROGINFO_T ProgressiveServer::findProgInfo(int32 jackpotID)
{
    PPROGINFO_T pProgInfo = (PPROGINFO_T) 0;
    PPROGINFO_T pProgSearch = pProgInfoList;

    if ( pProgSearch != (PPROGINFO_T) 0 )
    {
        do
        {
            if ( pProgSearch->jackpotID == jackpotID )
            {
                pProgInfo = pProgSearch;
            }
            pProgSearch = pProgSearch->next;
        } 
        while ( pProgSearch != pProgInfoList );
    }

    return pProgInfo;
}



/**
 *      insertProgInfo
 *          Create a new ProgInfo structure and initialize it.  Set
 *          the jackpotID to that given.  Insert the ProgInfo structure
 *          at the end of the list.
 *
 *      Parameters
 *          jackpotID   i
 *              The jackpotID used to identify the ProgInfo structure.
 *
 *      Returns
 *          PROGINFO_T *
 *              A pointer to the ProgInfo structure created.
 */

PPROGINFO_T ProgressiveServer::insertProgInfo(int32 jackpotID)
{
    PPROGINFO_T pProgInfo = new ProgInfo();

    pProgInfo->progressiveOn = false; //should default to off
	pProgInfo->fixedAmountMultiplier = 0;
    pProgInfo->funBetIndex = 0;
    pProgInfo->numRealBets = 0;
    pProgInfo->numFunBets = 0;
    pProgInfo->jackpotID = jackpotID;

    int32 i;
    for (i=0; i<PROGRESSIVE_BETS_TO_TRACK; i++)
    {
        pProgInfo->realBets[i].betTime = 0;
        pProgInfo->realBets[i].amtPutInJackpot = 0;
        pProgInfo->funBets[i].betTime = 0;
        pProgInfo->funBets[i].amtPutInJackpot = 0;
    }
    pProgInfo->realBetIndex = 0;
    pProgInfo->funBetIndex = 0;
    pProgInfo->lastRealBetTime = 0;
    pProgInfo->lastFunBetTime = 0;

    if ( pProgInfoList == (PPROGINFO_T) 0 )
    {
        //  Brand new list with no head.
        pProgInfoList = pProgInfo;
        pProgInfoList->next = pProgInfo;
        pProgInfoList->prev = pProgInfo;
    }
    else
    {
        //  Existing list, add it to the end.
        pProgInfo->next = pProgInfoList;
        pProgInfo->prev = pProgInfoList->prev;
        pProgInfoList->prev->next = pProgInfo;
        pProgInfoList->prev = pProgInfo;
    }

    return pProgInfo;
}


/**
 *      delProgInfoList
 *          Clean up the pProgInfoList and delete all the ProgInfo
 *          structures.
 *
 *      Parameters
 *          void
 *
 *      Returns
 *          void
 */
void ProgressiveServer::delProgInfoList()
{
    if ( pProgInfoList != (PPROGINFO_T) 0 )
    {
        // Keep going until only the head is left.
        while ( pProgInfoList != pProgInfoList->next )
        {
            PPROGINFO_T pProgInfoDel = pProgInfoList->prev;
    
            pProgInfoList->prev = pProgInfoDel->prev;
            pProgInfoDel->prev->next = pProgInfoList;
    
            delete pProgInfoDel;
        }
    
        //  Delete the head
        delete pProgInfoList;
    }
}

bool8 ProgressiveServer::jackpotAdjust(int32 jackpotID, int32 jackpotAdjust,int32 &jackpot, bool8 forReal, int32 progressiveFixedAmountMultiplier, int32& multiBankPayout)
{	
	int32 result = ProgressiveTrackSQL::ExecFailed;
    if (tracker)
	{
		tracker->lock();
		result = ((ProgressiveTrackSQL*)tracker)->jackpotAdjust(jackpotID, jackpotAdjust, jackpot, forReal, ServerOpts::baseName, progressiveFixedAmountMultiplier, multiBankPayout);
		tracker->unlock();
	}
    return (bool8)(result == ProgressiveTrackSQL::NoError);	
}

bool8 ProgressiveServer::jackpotAdjustByBet(int32 jackpotID, int32 jackpotAdjust, int32 multiplier, int32 &jackpot, int32& increasedAmount, int32& multiBankBet, bool8 forReal, int32 progressiveFixedAmountMultiplier)
{	
	int32 result = ProgressiveTrackSQL::ExecFailed;
    if (tracker)
	{
		tracker->lock();
		result = ((ProgressiveTrackSQL*)tracker)->jackpotAdjustByBet(jackpotID, jackpotAdjust, multiplier, jackpot, increasedAmount, multiBankBet, forReal, ServerOpts::baseName, progressiveFixedAmountMultiplier);
		tracker->unlock();
	}
    return (bool8)(result == ProgressiveTrackSQL::NoError);	
}

bool8 ProgressiveServer::jackpotAdjustByPercent(int32 jackpotID, int32 jackpotAdjust,int32 &jackpot, bool8 forReal, int32 progressiveFixedAmountMultiplier, int32& multiBankPayout)
{	
	int32 result = ProgressiveTrackSQL::ExecFailed;
    if (tracker)
	{
		tracker->lock();
		result = ((ProgressiveTrackSQL*)tracker)->jackpotAdjustByPercent(jackpotID, jackpotAdjust, jackpot, forReal, ServerOpts::baseName, progressiveFixedAmountMultiplier, multiBankPayout);
		tracker->unlock();
	}
    return (bool8)(result == ProgressiveTrackSQL::NoError);	
}
